#include "ftpclient.h"
#include <QDebug>
#include <QtConcurrent>
#include <qstring.h>
struct ProgressData {
    FTPClient* ftpClient;
    QString fileName;
};

// 清理远程路径
QString cleanRemotePath(const QString& path)
{
    QString cleaned = path;
    cleaned = cleaned.replace("//", "/");  // 替换双斜杠为单斜杠
    if (cleaned.startsWith("/")) {
        cleaned = cleaned.mid(1);  // 移除开头的斜杠
    }
    return cleaned;
}
FTPClient::FTPClient(QObject *parent)
    : QObject{parent}, m_initialized(false), m_lastProgress(-1),m_operationInProgress(0)
{
    curl_global_init(CURL_GLOBAL_ALL);
}

FTPClient::~FTPClient()
{
    curl_global_cleanup();
}

bool FTPClient::init()
{
    if (m_initialized) return true;

    m_curl = curl_easy_init();
    if (!m_curl) {
        qDebug() << "curl_easy_init failed";
        return false;
    }

    curl_easy_setopt(m_curl, CURLOPT_TIMEOUT, 30L);
    curl_easy_setopt(m_curl, CURLOPT_FOLLOWLOCATION, 1L);
    m_initialized = true;
    return true;
}

QFuture<bool> FTPClient::uploadFileAsync(const QString& ftpUrl, const QString& username, const QString& password, const QString& localFile, const QString& remoteFile)
{
    return QtConcurrent::run([=]() mutable {
        m_operationInProgress = 3;
        m_lastProgress = -1;

        CURL* curl = createCurlHandle();
        if (!curl) {
            qDebug() << "Failed to create curl handle for upload";
            m_operationInProgress = 0;
            emit uploadError(localFile, "Failed to create curl handle");
            return false;
        }

        // 启用详细调试输出
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

        QFile localFileObj(localFile);
        if (!localFileObj.open(QIODevice::ReadOnly)) {
            qDebug() << "本地文件打开失败：" << localFile;
            curl_easy_cleanup(curl);
            m_operationInProgress = 0;
            emit uploadError(localFile, "本地文件打开失败");
            return false;
        }

        qint64 fileSize = localFileObj.size();
        if (fileSize <= 0) {
            qDebug() << "文件大小为0：" << localFile;
            localFileObj.close();
            curl_easy_cleanup(curl);
            m_operationInProgress = 0;
            emit uploadError(localFile, "文件大小为0");
            return false;
        }

        // 清理远程路径
        QString cleanRemote = cleanRemotePath(remoteFile);
        QString fullUrl = ftpUrl;
        if (!ftpUrl.endsWith("/") && !cleanRemote.startsWith("/")) {
            fullUrl += "/";
        }
        fullUrl += cleanRemote;

        curl_easy_setopt(curl, CURLOPT_URL, fullUrl.toUtf8().constData());
        curl_easy_setopt(curl, CURLOPT_USERPWD, (username + ":" + password).toUtf8().constData());

        // 设置为上传模式
        curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
        curl_easy_setopt(curl, CURLOPT_READFUNCTION, uploadWriteCallback);
        curl_easy_setopt(curl, CURLOPT_READDATA, &localFileObj);

        // 启用自动创建目录
        curl_easy_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS, 1L);

        // 尝试不同的FTP模式
        curl_easy_setopt(curl, CURLOPT_FTP_USE_EPSV, 0L);  // 禁用EPSV
        curl_easy_setopt(curl, CURLOPT_FTPPORT, "-");      // 尝试主动模式

        curl_easy_setopt(curl, CURLOPT_FTPLISTONLY, 0L);
        curl_easy_setopt(curl, CURLOPT_TRANSFERTEXT, 0L);  // 二进制模式

        // 上传进度回调
        UploadData uploadData;
        uploadData.ftpClient = this;
        uploadData.fileName = QFileInfo(localFile).fileName();
        uploadData.file = &localFileObj;
        uploadData.fileSize = fileSize;

        curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
        curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, uploadProgressCallback);
        curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &uploadData);

        qDebug() << "开始上传: " << localFile << " 到 " << fullUrl;
        CURLcode res = curl_easy_perform(curl);
        localFileObj.close();
        curl_easy_cleanup(curl);
        m_operationInProgress = 0;

        if (res != CURLE_OK) {
            qDebug() << "上传失败：" << curl_easy_strerror(res);
            emit uploadError(localFile, "上传失败: " + QString(curl_easy_strerror(res)));
            return false;
        }

        emit uploadFinished(localFile, true);
        emit uploadProgress(uploadData.fileName, 100);
        return true;
        });
}

QFuture<bool> FTPClient::downloadFileAsync(const QString &ftpUrl, const QString &username, const QString &password, const QString &remoteFile, const QString &localFile)
{
    return QtConcurrent::run([=]() mutable {
        // 设置操作状态
        m_operationInProgress = 1;
        m_lastProgress = -1;

        CURL* curl = createCurlHandle();
        if (!curl) {
            qDebug() << "Failed to create curl handle";
            m_operationInProgress = 0;
            return false;
        }

        QFile localFileObj(localFile);
        if (!localFileObj.open(QIODevice::WriteOnly)) {
            qDebug() << "本地文件打开失败：" << localFile;
            curl_easy_cleanup(curl);
            m_operationInProgress = 0;
            return false;
        }

        QString fullUrl = ftpUrl;
        if (!ftpUrl.endsWith("/") && !remoteFile.startsWith("/")) {
            fullUrl += "/";
        }
        fullUrl += remoteFile;

        curl_easy_setopt(curl, CURLOPT_URL, fullUrl.toUtf8().constData());
        curl_easy_setopt(curl, CURLOPT_USERPWD, (username + ":" + password).toUtf8().constData());
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &localFileObj);

        curl_easy_setopt(curl, CURLOPT_FTP_USE_EPSV, 1L);
        curl_easy_setopt(curl, CURLOPT_TRANSFERTEXT, 0L);

        ProgressData progressData;
        progressData.ftpClient = this;
        progressData.fileName = QFileInfo(remoteFile).fileName();

        curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
        curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progressCallback);
        curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &progressData);

        CURLcode res = curl_easy_perform(curl);
        localFileObj.close();

        curl_easy_cleanup(curl);
        m_operationInProgress = 0;

        if (res != CURLE_OK) {
            qDebug() << "下载失败：" << curl_easy_strerror(res);
            return false;
        }

        // 确保下载完成信号在主线程发射
        QMetaObject::invokeMethod(this, [this, progressData]() {
            emit downloadProgress(progressData.fileName, 100);
            }, Qt::QueuedConnection);

        return true;
        });
}



CURL* FTPClient::createCurlHandle()
{
    CURL* curl = curl_easy_init();
    if (curl) {
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L);
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
        curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L);
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
    }
    return curl;
}

size_t FTPClient::writeCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
    QFile* file = static_cast<QFile*>(userp);
    if (!file) return 0;

    size_t bytesWritten = size * nmemb;
    /*qDebug() << "写入数据:" << bytesWritten << "字节" << "累计大小:" << file->size();*/

    return file->write(static_cast<const char*>(contents), bytesWritten);
}

int FTPClient::progressCallback(void* clientp, double dltotal, double dlnow, double ultotal, double ulnow)
{
    Q_UNUSED(ultotal);
    Q_UNUSED(ulnow);

    ProgressData* data = static_cast<ProgressData*>(clientp);
    if (!data || !data->ftpClient || dltotal <= 0)
        return 0;

    int progress = static_cast<int>((dlnow / dltotal) * 100);
    /*qDebug() << "下载进度:" << progress << "%"
        << "已下载:" << static_cast<qint64>(dlnow) << "字节"
        << "总大小:" << static_cast<qint64>(dltotal) << "字节";*/

    if (progress - data->ftpClient->m_lastProgress >= 5 || progress == 100) {
        data->ftpClient->m_lastProgress = progress;

        emit data->ftpClient->downloadProgress(data->fileName, progress);
    }

    return 0;
}

size_t FTPClient::listCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
    size_t realsize = size * nmemb;
    QStringList* fileList = static_cast<QStringList*>(userp);

    QString data = QString::fromUtf8(static_cast<char*>(contents), realsize);
    QStringList lines = data.split('\n', Qt::SkipEmptyParts);

    for (const QString& line : lines) {
        QStringList parts = line.split(' ', Qt::SkipEmptyParts);
        if (parts.size() >= 9) {
            QString filename = parts.last();
            fileList->append(filename);
        }
        else if (parts.size() == 1) {
            fileList->append(parts.first());
        }
    }
    return realsize;
}
size_t FTPClient::uploadWriteCallback(void* contents, size_t size, size_t nmemb, void* userp)
{
    QFile* file = static_cast<QFile*>(userp);
    if (!file || !file->isOpen()) return 0;

    size_t bytesToRead = size * nmemb;
    QByteArray data = file->read(bytesToRead);
    memcpy(contents, data.constData(), qMin(bytesToRead, static_cast<size_t>(data.size())));
    return data.size();
}

int FTPClient::uploadProgressCallback(void* clientp, double dltotal, double dlnow, double ultotal, double ulnow)
{
    Q_UNUSED(ultotal);
    Q_UNUSED(ulnow);
    UploadData* data = static_cast<UploadData*>(clientp);
    if (!data || !data->ftpClient || data->fileSize <= 0)
        return 0;
    int progress = static_cast<int>((dlnow / data->fileSize) * 100);
    if (progress > 100) progress = 100;
    if (progress - data->ftpClient->m_lastProgress >= 5 || progress == 100) {
        data->ftpClient->m_lastProgress = progress;
        emit data->ftpClient->uploadProgress(data->fileName, progress);
    }
    return 0;
}

void FTPClient::manageUploadTask(QFuture<bool> future, const QString &fileName)
{

}

QFuture<QStringList> FTPClient::getDirectoryListingAsync(const QString &ftpUrl, const QString &username, const QString &password, const QString &remoteDir)
{
    // 用 lambda 封装目录列表获取逻辑，放到后台线程
    return QtConcurrent::run([=]() mutable {
        // 设置操作状态
        m_operationInProgress = 2;

        CURL* curl = createCurlHandle();
        if (!curl) {
            QMetaObject::invokeMethod(this, [this]() {
                emit directoryListingError("初始化FTP客户端失败");
                }, Qt::QueuedConnection);
            m_operationInProgress = 0;
            return QStringList();
        }

        QStringList fileList;
        QString fullUrl = ftpUrl;

        if (!ftpUrl.endsWith("/") && !remoteDir.isEmpty() && !remoteDir.startsWith("/")) {
            fullUrl += "/";
        }
        fullUrl += remoteDir;

        if (!fullUrl.endsWith("/") && !remoteDir.isEmpty()) {
            fullUrl += "/";
        }

        curl_easy_setopt(curl, CURLOPT_URL, fullUrl.toUtf8().constData());
        curl_easy_setopt(curl, CURLOPT_USERPWD, (username + ":" + password).toUtf8().constData());
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, listCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &fileList);
        curl_easy_setopt(curl, CURLOPT_FTPLISTONLY, 1L);
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L);

        CURLcode res = curl_easy_perform(curl);
        curl_easy_cleanup(curl);
        m_operationInProgress = 0;

        if (res != CURLE_OK) {
            QString error = "获取目录列表失败: " + QString(curl_easy_strerror(res));
            QMetaObject::invokeMethod(this, [this, error]() {
                emit directoryListingError(error);
                }, Qt::QueuedConnection);
            return QStringList();
        }

        QMetaObject::invokeMethod(this, [this, fileList]() {
            emit directoryListingReady(fileList);
            }, Qt::QueuedConnection);

        return fileList;
        });
}
